package com.huan;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * @author chenbin78
 * @version 1.0
 * @create_date 2021/4/19 10:46
 */
public class UnsafeCasTest {

    private Map<Integer, Integer> map = new HashMap<>();

    private Integer count = 1;

    //使用volatile保证flag在两个线程中的可见性
    volatile int flag = 0;

    private static Unsafe unsafe;
    private static Long flagOffset;

    static {
        try {
            unsafe = getUnsafeInstance();
            //获取flag的偏移量, 为CAS操作做准备
            //getDeclaredField()与getField
            flagOffset = unsafe.objectFieldOffset(UnsafeCasTest.class.getDeclaredField("flag"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取unsafe实例
    public static Unsafe getUnsafeInstance() throws Exception {
        // 通过反射获取rt.jar下的Unsafe类
        Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafeInstance.setAccessible(true);
        // return (Unsafe) theUnsafeInstance.get(null);是等价的
        return (Unsafe) theUnsafeInstance.get(Unsafe.class);
    }

    public void put() {
        for (int i = 0; i < 10; i++) {
            for (;;) {
                if (flag == 0) {
                    break;
                }
            }
            map.put(count, count);
            System.out.println(Thread.currentThread().getName() + " put：" + count);
            count ++ ;
            int tmp = flag;
            //使用CAS赋值
            unsafe.compareAndSwapInt(this, flagOffset, tmp, 1);
        }
        System.out.println(Thread.currentThread().getName() + "执行完毕！");
    }

    public void get() {
        for (int i = 0; i < 10; i++) {
            for (;;) {
                if (flag == 1) {
                    break;
                }
            }
            Integer integer = map.get(count - 1);
            System.out.println(Thread.currentThread().getName() + " get：" + integer);
            int tmp = flag;
            unsafe.compareAndSwapInt(this, flagOffset, tmp, 0);
        }
        System.out.println(Thread.currentThread().getName() + "执行完毕！");
    }
}
